﻿using AutomaticPush.Models;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
using System.Net;
using System.Text;
using System.Text.Json;

namespace AutomaticPush.Common
{
    public class WebApiExt
    {

        /// <summary>
        /// 服务实例
        /// </summary>
        public IServiceProvider _ss { get => Program.Provider; }
        #region CallApi
        public async Task<ApiResult<T>> CallAPI<T>(string url, HttpMethodEnum method, HttpContent content, int? timeout = null, string proxy = null, Dictionary<string, string> headers = null) where T : class
        {
            ApiResult<T> rv = new ApiResult<T>();
            try
            { 
                if (string.IsNullOrEmpty(url))
                {
                    return rv;
                }
                //新建http请求
                HttpClient client = _ss.GetRequiredService<HttpClient>();

                if (headers != null)
                {
                    foreach (var item in headers)
                    {
                        if (client.DefaultRequestHeaders.Any(x => x.Key == item.Key) == false)
                        {
                            client.DefaultRequestHeaders.Add(item.Key, item.Value);
                        }
                    }
                }

                //如果配置了代理，则使用代理
                //设置超时
                if (timeout.HasValue)
                {
                    client.Timeout = new TimeSpan(0, 0, 0, timeout.Value, 0);
                }
                //填充表单数据
                HttpResponseMessage res = null;
                switch (method)
                {
                    case HttpMethodEnum.GET:
                        res = await client.GetAsync(url);
                        break;
                    case HttpMethodEnum.POST:
                        res = await client.PostAsync(url, content);
                        break;
                    case HttpMethodEnum.PUT:
                        res = await client.PutAsync(url, content);
                        break;
                    case HttpMethodEnum.DELETE:
                        res = await client.DeleteAsync(url);
                        break;
                    default:
                        break;
                }
                if (res == null)
                {
                    return rv;
                }
                rv.StatusCode = res.StatusCode;
                if (res.IsSuccessStatusCode == true)
                {
                    Type dt = typeof(T);
                    if (dt == typeof(byte[]))
                    {
                        rv.Data = await res.Content.ReadAsByteArrayAsync() as T;
                    }
                    else
                    {
                        string responseTxt = await res.Content.ReadAsStringAsync();
                        if (dt == typeof(string))
                        {
                            rv.Data = responseTxt as T;
                        }
                        else
                        {
                            rv.Data = JsonSerializer.Deserialize<T>(responseTxt, GlobalData.DefaultJsonOption);
                        }
                    }
                }
                else
                {
                    string responseTxt = await res.Content.ReadAsStringAsync();
                    if (res.StatusCode == System.Net.HttpStatusCode.BadRequest)
                    {

                        try
                        {
                            rv.Errors = JsonSerializer.Deserialize<ErrorObj>(responseTxt, GlobalData.DefaultJsonOption);
                        }
                        catch { }
                    }
                    rv.ErrorMsg = responseTxt;
                }

                return rv;
            }
            catch (Exception ex)
            {
                rv.ErrorMsg = ex.ToString();
                return rv;
            }
        }

        /// <summary>
        /// 使用Get方法调用api
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="domainName">Appsettings中配置的Domain key</param>
        /// <param name="url">调用地址</param>
        /// <param name="timeout">超时时间，单位秒</param>
        /// <param name="proxy">代理地址</param>
        /// <param name="headers">http headers</param>
        /// <returns></returns>
        public async Task<ApiResult<T>> CallAPI<T>(string url, int? timeout = null, string proxy = null, Dictionary<string, string> headers = null) where T : class
        {
            HttpContent content = null;
            //填充表单数据
            return await CallAPI<T>(url, HttpMethodEnum.GET, content, timeout, proxy, headers);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="domainName">Appsettings中配置的Domain key</param>
        /// <param name="url">调用地址</param>
        /// <param name="method">调用方式</param>
        /// <param name="postdata">提交字段</param>
        /// <param name="timeout">超时时间，单位秒</param>
        /// <param name="proxy">代理地址</param>
        /// <param name="headers">http headers</param>
        /// <returns></returns>
        public async Task<ApiResult<T>> CallAPI<T>(string url, HttpMethodEnum method, IDictionary<string, string> postdata, int? timeout = null, string proxy = null, Dictionary<string, string> headers = null) where T : class
        {
            HttpContent content = null;
            //填充表单数据
            if (!(postdata == null || postdata.Count == 0))
            {
                List<KeyValuePair<string, string>> paras = new List<KeyValuePair<string, string>>();
                foreach (string key in postdata.Keys)
                {
                    paras.Add(new KeyValuePair<string, string>(key, postdata[key]));
                }
                content = new FormUrlEncodedContent(paras);
            }
            return await CallAPI<T>(url, method, content, timeout, proxy, headers);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="domainName">Appsettings中配置的Domain key</param>
        /// <param name="url">调用地址</param>
        /// <param name="method">调用方式</param>
        /// <param name="postdata">提交的object，会被转成json提交</param>
        /// <param name="timeout">超时时间，单位秒</param>
        /// <param name="proxy">代理地址</param>
        /// <param name="headers">http headers</param>
        /// <returns></returns>
        public async Task<ApiResult<T>> CallAPI<T>(string url, HttpMethodEnum method, object postdata, Dictionary<string, string> headers = null, int? timeout = null, string proxy = null) where T : class
        {
            var JsonStr = JsonSerializer.Serialize(postdata, GlobalData.DefaultPostJsonOption);
            HttpContent content = new StringContent(JsonStr, Encoding.UTF8, "application/json");
            return await CallAPI<T>(url, method, content, timeout, proxy, headers);
        }

        /// <summary>
        /// Post提交
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="url"></param>
        /// <param name="postdata"></param>
        /// <param name="headers"></param>
        /// <param name="timeout"></param>
        /// <param name="proxy"></param>
        /// <returns></returns>
        public async Task<ApiResult<T>> PostAPI<T>(string url,object postdata, Dictionary<string, string> headers = null, int? timeout = null, string proxy = null) where T : class
        {
            var method = HttpMethodEnum.POST;
            var JsonStr = JsonSerializer.Serialize(postdata, GlobalData.DefaultPostJsonOption);
            HttpContent content = new StringContent(JsonStr, Encoding.UTF8, "application/json");
            return await CallAPI<T>(url, method, content, timeout, proxy, headers);
        }


        public async Task<ApiResult<string>> CallAPI(string url, HttpMethodEnum method, HttpContent content, int? timeout = null, string proxy = null, Dictionary<string, string> headers = null)
        {
            return await CallAPI<string>(url, method, content, timeout, proxy, headers);
        }

        /// <summary>
        /// 使用Get方法调用api
        /// </summary>
        /// <param name="domainName">Appsettings中配置的Domain key</param>
        /// <param name="url">调用地址</param>
        /// <param name="timeout">超时时间，单位秒</param>
        /// <param name="proxy">代理地址</param>
        /// <param name="headers">http headers</param>
        /// <returns></returns>
        public async Task<ApiResult<string>> CallAPI(string url, int? timeout = null, string proxy = null, Dictionary<string, string> headers = null)
        {
            return await CallAPI<string>(url, timeout, proxy, headers);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="domainName">Appsettings中配置的Domain key</param>
        /// <param name="url">调用地址</param>
        /// <param name="method">调用方式</param>
        /// <param name="postdata">提交字段</param>
        /// <param name="timeout">超时时间，单位秒</param>
        /// <param name="proxy">代理地址</param>
        /// <param name="headers">自定义header</param>
        /// <returns></returns>
        public async Task<ApiResult<string>> CallAPI(string url, HttpMethodEnum method, IDictionary<string, string> postdata, int? timeout = null, string proxy = null, Dictionary<string, string> headers = null)
        {
            return await CallAPI<string>(url, method, postdata, timeout, proxy, headers);

        }
         

        public void Dispose()
        {

        }

        #endregion

        #region 旧方法
        /// <summary>
        /// Post提交
        /// <para>url:请求路径,jsonstring:JSON数据,header:header请求头</para>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="url">请求路径</param>
        /// <param name="jsonstring">JSON数据</param>
        /// <param name="header">header请求头</param>
        /// <param name="dic"></param>
        /// <returns></returns>
        public static T PostJson<T>(string url, string jsonstring = "", Dictionary<string, string> header = null, Dictionary<string, string> dic = null)
        {
            string result = PostJson(url, dic, jsonstring, header);
            if (result == "")
                return default;
            return JsonSerializer.Deserialize<T>(result);

        }



        /// <summary>
        /// Post提交
        /// </summary>
        /// <param name="url"></param>
        /// <param name="dic"></param>
        /// <returns></returns> 
        public static String PostJson(string url, Dictionary<string, string> dic = null, string jsonstring = "", Dictionary<string, string> header = null)
        {
            GC.Collect();
            string result = "";
            DateTime startTime = DateTime.Now;
            string[] strTime = { "-1", "500" };
            try
            {
                /**
                 * 构造请求参数
                 * **/
                if (dic != null && dic.Count > 0)
                {
                    var vDic = from objDic in dic orderby objDic.Key ascending select objDic;
                    var sb = new StringBuilder();
                    foreach (var item in vDic)
                    {
                        sb.AppendFormat("{0}={1}&", item.Key, item.Value);
                    }
                    var mt = sb.ToString().TrimEnd('&');
                    url = url + "?" + mt;
                }

                ServicePointManager.DefaultConnectionLimit = 50;
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
                req.UseDefaultCredentials = true;
                req.Method = "POST";
                req.KeepAlive = true;
                req.Timeout = 30 * 10000;
                req.ContentType = "application/json;charset=UTF-8";

                // 添加header
                if (header != null && header.Count > 0)
                {
                    foreach (var item in header)
                    {
                        req.Headers.Add(item.Key, item.Value);
                    }
                }
                #region 添加Post 参数

                byte[] data = Encoding.UTF8.GetBytes(jsonstring);
                req.ContentLength = data.Length;
                using (Stream reqStream = req.GetRequestStream())
                {
                    reqStream.Write(data, 0, data.Length);
                    reqStream.Close();
                }

                #endregion
                HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
                Stream stream = resp.GetResponseStream();

                if (resp.StatusCode == HttpStatusCode.OK)//响应成功
                {
                    DateTime endTime = DateTime.Now;
                    strTime[0] = Convert.ToInt32((endTime - startTime).TotalMilliseconds).ToString();//获取响应时间 
                    strTime[1] = "200";
                    //获取响应内容
                    using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                    {
                        result = reader.ReadToEnd();
                    }
                }
                else
                {
                    strTime[1] = "500,无法连接到远程服务器";
                }

                if (req != null)
                {
                    req.Abort();
                }
                if (resp != null)
                {
                    resp.Close();
                }
                //ErrorLog.WriteLog("OpenAPIAction_DomainService-post-Result-url:" + url + jsonstring, "Post");
            }
            catch (System.Net.WebException ex) //by txwtech
            {
                var strError = ex.Message;
                using (WebResponse res = ex.Response)
                {
                    var httpResponse = (HttpWebResponse)res;
                    using (Stream data = res.GetResponseStream())
                    {
                        using (StreamReader reader = new StreamReader(data))
                        {
                            strError = reader.ReadToEnd();
                        }
                    }
                    //  statusCode = httpResponse.StatusCode;
                }
                //if (ex.Status != WebExceptionStatus.ProtocolError)
                //    throw;
                result = strError;
            }
            catch (Exception ex)
            {
            }
            return result;
        }


        #endregion


    }
}
